#include "StdAfx.h"
#include "XMLLoader.h"
#include "SceneLoader/SceneLoader.h"
#include "Sphere.h"
#include "PointLight.h"
#include "DirectionalLight.h"
#include "SpotLight.h"
#include "CSGUnion.h"
#include "CSGDifference.h"
#include "CSGIntersection.h"

void XMLLoader::LoadScene(const string& strFileName, 
						  vector<CGeometryPtr>& vGeometries,
						  vector<CCameraPtr>& vCameras,
						  vector<CLightPtr>& vLights)
{
	scene::Scene loadedScene = scene::loadScene(strFileName);

	// convert camera
	scene::Camera& loadedCamera = loadedScene.camera;
	CCameraPtr spNewCamera(new CCamera);
	spNewCamera->Init(CVector3D(loadedCamera.x, loadedCamera.y, loadedCamera.z),
				      loadedCamera.fov,
				      CVector3D(loadedCamera.lookAtX, loadedCamera.lookAtY, loadedCamera.lookAtZ),
				      CVector3D(loadedCamera.upX, loadedCamera.upY, loadedCamera.upZ));
	vCameras.push_back(spNewCamera);

	// convert spheres
	vector<scene::Sphere>& loadedSpheres = loadedScene.spheres;
	vector<scene::Sphere>::const_iterator itSphere;
	for (itSphere = loadedSpheres.begin(); itSphere != loadedSpheres.end(); ++itSphere)
	{
		const scene::Sphere& loadedSphere = *itSphere;
		CSpherePtr spSphere(new CSphere);
		spSphere->Init(CVector3D(loadedSphere.x, loadedSphere.y, loadedSphere.z), loadedSphere.radius,
					   CColor4(loadedSphere.color.r, loadedSphere.color.g, loadedSphere.color.b, loadedSphere.color.a),
					   CMaterial(loadedSphere.material.reflectance, loadedSphere.material.refraction, loadedSphere.material.phongExponent));

		if (loadedSphere.keyFrames.size() != 0)
		{
			CTimeControllerPtr spTimeController(new CTimeController);
			for (size_t i = 0; i < loadedSphere.keyFrames.size(); ++i)
			{
				spTimeController->AddKey(loadedSphere.keyFrames[i].fTime, 
					CVector3D(loadedSphere.keyFrames[i].x, loadedSphere.keyFrames[i].y, loadedSphere.keyFrames[i].z));
			}
			spSphere->AttachTimeController(spTimeController);
		}
		vGeometries.push_back(spSphere);
	}

	// convert CSGs
	// union
	vector<scene::CSGUnion>& loadedCSGUnions = loadedScene.csgUnions;
	vector<scene::CSGUnion>::const_iterator itCSGUnion;
	for (itCSGUnion = loadedCSGUnions.begin(); itCSGUnion != loadedCSGUnions.end(); ++itCSGUnion)
	{
		const scene::CSGUnion& loadedCSGUnion = *itCSGUnion;

		const scene::Sphere& loadedSphereLeft = loadedCSGUnion.left;
		CSpherePtr spSphereLeft(new CSphere);
		spSphereLeft->Init(CVector3D(loadedSphereLeft.x, loadedSphereLeft.y, loadedSphereLeft.z), loadedSphereLeft.radius,
			CColor4(loadedSphereLeft.color.r, loadedSphereLeft.color.g, loadedSphereLeft.color.b, loadedSphereLeft.color.a),
			CMaterial(loadedSphereLeft.material.reflectance, loadedSphereLeft.material.refraction, loadedSphereLeft.material.phongExponent));

		// uses same color & material props
		const scene::Sphere& loadedSphereRight = loadedCSGUnion.right;
		CSpherePtr spSphereRight(new CSphere);
		spSphereRight->Init(CVector3D(loadedSphereRight.x, loadedSphereRight.y, loadedSphereRight.z), loadedSphereRight.radius,
			CColor4(loadedSphereLeft.color.r, loadedSphereLeft.color.g, loadedSphereLeft.color.b, loadedSphereLeft.color.a),
			CMaterial(loadedSphereLeft.material.reflectance, loadedSphereLeft.material.refraction, loadedSphereLeft.material.phongExponent));

		CCSGUnionPtr spCSGUnion(new CCSGUnion);
		CConstructiveSolidGeometryPtr spCSGLeft = spSphereLeft;
		CConstructiveSolidGeometryPtr spCSGRight = spSphereRight;
		spCSGUnion->Init(spCSGLeft, spCSGRight, spSphereLeft->GetColor(), spSphereLeft->GetMaterial());
		vGeometries.push_back(spCSGUnion);
	}

	// intersection
	vector<scene::CSGIntersection>& loadedCSGIntersections = loadedScene.csgIntersections;
	vector<scene::CSGIntersection>::const_iterator itCSGIntersection;
	for (itCSGIntersection = loadedCSGIntersections.begin(); itCSGIntersection != loadedCSGIntersections.end(); ++itCSGIntersection)
	{
		const scene::CSGIntersection& loadedCSGIntersection = *itCSGIntersection;

		const scene::Sphere& loadedSphereLeft = loadedCSGIntersection.left;
		CSpherePtr spSphereLeft(new CSphere);
		spSphereLeft->Init(CVector3D(loadedSphereLeft.x, loadedSphereLeft.y, loadedSphereLeft.z), loadedSphereLeft.radius,
			CColor4(loadedSphereLeft.color.r, loadedSphereLeft.color.g, loadedSphereLeft.color.b, loadedSphereLeft.color.a),
			CMaterial(loadedSphereLeft.material.reflectance, loadedSphereLeft.material.refraction, loadedSphereLeft.material.phongExponent));

		// uses same color & material props
		const scene::Sphere& loadedSphereRight = loadedCSGIntersection.right;
		CSpherePtr spSphereRight(new CSphere);
		spSphereRight->Init(CVector3D(loadedSphereRight.x, loadedSphereRight.y, loadedSphereRight.z), loadedSphereRight.radius,
			CColor4(loadedSphereLeft.color.r, loadedSphereLeft.color.g, loadedSphereLeft.color.b, loadedSphereLeft.color.a),
			CMaterial(loadedSphereLeft.material.reflectance, loadedSphereLeft.material.refraction, loadedSphereLeft.material.phongExponent));

		CCSGIntersectionPtr spCSGIntersection(new CCSGIntersection);
		CConstructiveSolidGeometryPtr spCSGLeft = spSphereLeft;
		CConstructiveSolidGeometryPtr spCSGRight = spSphereRight;
		spCSGIntersection->Init(spCSGLeft, spCSGRight, spSphereLeft->GetColor(), spSphereLeft->GetMaterial());
		vGeometries.push_back(spCSGIntersection);
	}

	// difference
	vector<scene::CSGDifference>& loadedCSGDifferences = loadedScene.csgDifferences;
	vector<scene::CSGDifference>::const_iterator itCSGDifference;
	for (itCSGDifference = loadedCSGDifferences.begin(); itCSGDifference != loadedCSGDifferences.end(); ++itCSGDifference)
	{
		const scene::CSGDifference& loadedCSGDifference = *itCSGDifference;

		const scene::Sphere& loadedSphereLeft = loadedCSGDifference.left;
		CSpherePtr spSphereLeft(new CSphere);
		spSphereLeft->Init(CVector3D(loadedSphereLeft.x, loadedSphereLeft.y, loadedSphereLeft.z), loadedSphereLeft.radius,
			CColor4(loadedSphereLeft.color.r, loadedSphereLeft.color.g, loadedSphereLeft.color.b, loadedSphereLeft.color.a),
			CMaterial(loadedSphereLeft.material.reflectance, loadedSphereLeft.material.refraction, loadedSphereLeft.material.phongExponent));

		// uses same color & material props
		const scene::Sphere& loadedSphereRight = loadedCSGDifference.right;
		CSpherePtr spSphereRight(new CSphere);
		spSphereRight->Init(CVector3D(loadedSphereRight.x, loadedSphereRight.y, loadedSphereRight.z), loadedSphereRight.radius,
			CColor4(loadedSphereLeft.color.r, loadedSphereLeft.color.g, loadedSphereLeft.color.b, loadedSphereLeft.color.a),
			CMaterial(loadedSphereLeft.material.reflectance, loadedSphereLeft.material.refraction, loadedSphereLeft.material.phongExponent));

		CCSGDifferencePtr spCSGDifference(new CCSGDifference);
		CConstructiveSolidGeometryPtr spCSGLeft = spSphereLeft;
		CConstructiveSolidGeometryPtr spCSGRight = spSphereRight;
		spCSGDifference->Init(spCSGLeft, spCSGRight, spSphereLeft->GetColor(), spSphereLeft->GetMaterial());
		vGeometries.push_back(spCSGDifference);
	}

	// convert lights
	vector<scene::Light>& loadedLights = loadedScene.lights;
	vector<scene::Light>::const_iterator itLight;
	for (itLight = loadedLights.begin(); itLight != loadedLights.end(); ++itLight)
	{
		const scene::Light& loadedLight = *itLight;
		CPointLightPtr spLight(new CPointLight);
		spLight->Init(CVector3D(loadedLight.x, loadedLight.y, loadedLight.z), loadedLight.ambient,
					   CColor4(loadedLight.color.r, loadedLight.color.g, loadedLight.color.b, loadedLight.color.a));
		vLights.push_back(spLight);
	}

	vector<scene::DirectionalLight>& loadedDirectionalLights = loadedScene.directionalLights;
	vector<scene::DirectionalLight>::const_iterator itDirLight;
	for (itDirLight = loadedDirectionalLights.begin(); itDirLight != loadedDirectionalLights.end(); ++itDirLight)
	{
		const scene::DirectionalLight& loadedLight = *itDirLight;
		CDirectionalLightPtr spLight(new CDirectionalLight);

		CVector3D vDirection = CVector3D(loadedLight.lookAtX - loadedLight.x,
			loadedLight.lookAtY - loadedLight.y,
			loadedLight.lookAtZ - loadedLight.z);
		vDirection = vDirection.Normalize();

		spLight->Init(CVector3D(loadedLight.x, loadedLight.y, loadedLight.z), 
			vDirection,	loadedLight.ambient,
			CColor4(loadedLight.color.r, loadedLight.color.g, loadedLight.color.b, loadedLight.color.a));
		vLights.push_back(spLight);
	}

	vector<scene::SpotLight>& loadedSpotLights = loadedScene.spotLights;
	vector<scene::SpotLight>::const_iterator itSpotLight;
	for (itSpotLight = loadedSpotLights.begin(); itSpotLight != loadedSpotLights.end(); ++itSpotLight)
	{
		const scene::SpotLight& loadedLight = *itSpotLight;
		CSpotLightPtr spLight(new CSpotLight);

		CVector3D vDirection = CVector3D(loadedLight.lookAtX - loadedLight.x,
			loadedLight.lookAtY - loadedLight.y,
			loadedLight.lookAtZ - loadedLight.z);
		vDirection = vDirection.Normalize();

		spLight->Init(CVector3D(loadedLight.x, loadedLight.y, loadedLight.z), 
			vDirection,	loadedLight.ambient,
			CColor4(loadedLight.color.r, loadedLight.color.g, loadedLight.color.b, loadedLight.color.a),
			loadedLight.cutOff, loadedLight.exponent);
		vLights.push_back(spLight);
	}
}